#include <kernel.h>
#include <pa4.h>

/*
 * Part A 4/4. buf_put()
 * buf_put() processes each write request.
 * If policy is POLICY_WRITE_THROUGH,
 *     then find a buffer that already stores the block_no block, stores new data to it
 *     and finally store the data into disk.
 * Otherwise (POLICY_DELAYED_WRITE),
 *     then you have to handle requests based on the policy.
 */
extern dsk_buffer_p findNode(int block_no,int pdev);
extern void evict(int count);
extern void modeToHead(int block_no,struct devsw *pdev);
extern int currpid;

int buf_put(struct devsw *pdev, int block_no, char *buffer, int policy)
{
	STATWORD ps;
	//disable(ps);
	dsk_buffer_p buf_blk;
	int counter=0;
	
	
	if(pdev==&devtab[DISK0])
	{
	//	restore(ps);
	 	while(semaphoredsk0[block_no] == 1)
        	{
	        	//kprintf("Disk 1 Another process has already requested for block no %d hence suspending this process till the block is fetched\n",block_no);
			counter++;
		//	if(counter>500)
		//	break;
	        	resched();
        	}
		disable(ps);
		semaphoredsk0[block_no]=1;
		//kprintf("\nDISK 1 Block %d Requested and set to %d by PID %d",block_no,semaphoredsk0[block_no],currpid);
	}
	else
	{
		//restore(ps);
	 	while(semaphoredsk1[block_no] == 1)
        	{
	        	//kprintf("Disk 2 Another process has already requested for block no %d hence suspending this process till the block is fetched\n",block_no);
			counter++;
		//	if(counter>500)
		//	break;
	        	resched();
        	}
		disable(ps);
		semaphoredsk1[block_no]=1;
		//kprintf("\nDISK 2 Block %d Requested and set to %d by PID %d",block_no,semaphoredsk1[block_no],currpid);
	}

	buf_blk=findNode(block_no,pdev);
	
	if(buf_blk!=NULL)//present in buffer 
	{
		buf_blk->data=buffer;
		modeToHead(block_no,pdev);
		if(policy == POLICY_WRITE_THROUGH)
		{
			
			dskwrite(pdev,buf_blk->data,block_no,1);
			if(pdev==&devtab[DISK0])
			semaphoredsk0[block_no]=0;
			else
			semaphoredsk1[block_no]=0;
			restore(ps);
			return OK;
		}
		else
		{
			buf_blk->dirty = 1;
			if(pdev==&devtab[DISK0])
			semaphoredsk0[block_no]=0;
			else
			semaphoredsk1[block_no]=0;
			restore(ps);
			return OK;
		}
	}
	else//not present in buffer
	{
		buf_blk=getmem(sizeof(struct buf));
		//printf("\nBlock to be wrriten Not present, Block is %d  buf_blk is %d",block_no,buf_blk);
		if((buf_head)&&(buf_count==PA4_BUFFER_SIZE))
		{
		//	printf("\nEntered to remove tail");
			evict(1);
			
		}
//		sleep(10);
		//if(!buf_head)
		//buf_head=buf_blk;
		//printf("\n IN HERE ? ");
		buf_blk->block_no = block_no;
		buf_blk->pdev = pdev;
		buf_blk->size = 128;
//		printf("\nBuffer is %d",buffer);
		buf_blk->data = buffer;
	//	printf("\nBuf_PUT : First data :%d Last Data %d",*((char *)(buf_blk->data)),*((char *)(buf_blk->data+127)));
//		printf("\n Buf_head is %d",buf_head);
		buf_blk->next = buf_head;
		buf_head=buf_blk;
//		printf("\nBuf head is now %d",buf_head);
		if(buf_count<PA4_BUFFER_SIZE)
		buf_count++;
		//printf("buffer count is %d",buf_count);
		if(policy == POLICY_WRITE_THROUGH)
		{
		//	printf("\n I CAME HERE AND DID A DISK WRITE");
			buf_blk->dirty=0;
			dskwrite(pdev,buf_blk->data,block_no,1);
		//	printf("\n DISK WRITE COMPLETE I GUESS");
			if(pdev==&devtab[DISK0])
			{
				semaphoredsk0[block_no]=0;
				//kprintf("\nDISK 1 Block %d set to %d by PID %d",block_no,semaphoredsk0[block_no],currpid);
			}
			else
			{
			semaphoredsk1[block_no]=0;
			//kprintf("\nDISK 2 Block %d set to %d by PID %d",block_no,semaphoredsk1[block_no],currpid);
			}
		//	printf("\n RETURNING NOW ");
			restore(ps);
			return OK;
		}
		else
		{
			buf_blk->dirty = 1;
			if(pdev==&devtab[DISK0])
			{
			semaphoredsk0[block_no]=0;
			//kprintf("\nDISK 1 Block %d set to %d by PID %d",block_no,semaphoredsk0[block_no],currpid);
			}
			else
			{
			semaphoredsk1[block_no]=0;
			//kprintf("\nDISK 2 Block %d set to %d by PID %d",block_no,semaphoredsk1[block_no],currpid);
			}
			restore(ps);
			return OK;
		}
	}
	
}

